package com.dysoft.flesh;

import com.dysoft.bones.DataManager;

import java.util.Collection;

/**
 * @author Sean Micklethwaite
 *         18-Aug-2010
 */
public class LightingShader implements Shader {
	final Shader shader;
	final int maxLights;
	final VecArrayUniform lights, colours;
	final FloatArrayUniform dist, spec;

	public LightingShader(Shader shader, int maxLights) {
		this.shader = shader;
		this.maxLights = maxLights;
		this.lights = new VecArrayUniform("lights");
		this.colours = new VecArrayUniform("lights_color");
		this.dist = new FloatArrayUniform("lights_dist");
		this.spec = new FloatArrayUniform("lights_spec");
	}

	public void set(int i, Float [] pos, Float [] colour, Float dist, Float spec) {
		lights.set(i, pos);
		colours.set(i, colour);
		this.dist.set(i, dist);
		this.spec.set(i, spec);
	}
	public Uniform<Integer> uniform(String name, int val) {
		return shader.uniform(name, val);
	}

	public Uniform<Float> uniform(String name, float val) {
		return shader.uniform(name, val);
	}

	public Uniform<Float[]> uniform(String name, Float[] val) {
		return shader.uniform(name, val);
	}

	public void activate(RenderContext ctx) throws DataManager.DataObject.NotPresentException {
		shader.activate(ctx);
	}

	public void deactivate(RenderContext ctx) throws DataManager.DataObject.NotPresentException {
		shader.deactivate(ctx);
	}

	public Component getComponent(Type type) {
		return shader.getComponent(type);
	}

	public Collection<? extends Uniform<?>> getUniforms() {
		return shader.getUniforms();
	}

	class VecArrayUniform implements Uniform<Float [][]> {
		final Float [][] val = new Float [maxLights][3];
		final String name;

		VecArrayUniform(String name) {
			Float [] z = new Float [] {0f,0f,0f};
			for(int i = 0; i < maxLights; i++) {
				set(i, z);
				shader.uniform(name + "[" + i + "]", val[i]);
			}
			this.name = name;
		}

		public Float[][] getVal() {
			return val;
		}

		public void setVal(Float[][] val) {
			for(int i = 0; i < Math.min(maxLights, val.length); i++) {
				set(i, val[i]);
			}
		}

		public void set(int i, Float [] val) {
			System.arraycopy(val, 0, this.val[i], 0, 3);
		}

		public String getName() {
			return name;
		}
	}

	class FloatArrayUniform implements Uniform<Float []> {
		final Uniform<Float> [] val = new Uniform [maxLights];
		final String name;

		FloatArrayUniform(String name) {
			for(int i = 0; i < maxLights; i++) {
				val[i] = shader.uniform(name + "[" + i + "]", 0f);
			}
			this.name = name;
		}

		public Float[] getVal() {
			Float [] v = new Float [maxLights];
			for(int i = 0; i < maxLights; i++) {
				v[i] = val[i].getVal();
			}
			return v;
		}

		public void setVal(Float[] val) {
			for(int i = 0; i < Math.min(maxLights, val.length); i++) {
				set(i, val[i]);
			}
		}

		public void set(int i, Float val) {
			this.val[i].setVal(val);
		}

		public String getName() {
			return name;
		}
	}

	public Shader getShader() {
		return shader;
	}
}
